# -*- coding: utf-8 -*-            
# @Time : 2024/6/10 16:26
# @Author  : lining
# @FileName: elementOpt.py
# @Description: 元素操作类
from Handle.handle_log import log
from Handle.handle_exception import NoSuchElementException, NoSuchLocatorException
from Core.waitOpt import Wait


class Element:
    # 元素操作类
    def __init__(self, page):
        self.page = page
        self.wait = Wait(self.page)

    # 查找元素--单个
    def element_find_element(self, selector):
        """
        :param selector: 定位方式,列表[定位方式locator或get_by，定位内容，参数传字典] locator用locator定位，by_xxx用get_by定位
        :return: 返回元素第一个
        """
        try:
            eles = self.find_elements(selector)
            # 长度>=1返回第一个元素，否则抛出异常
            if eles.count() > 0:
                log.log_info(f'查找第一个元素成功: {selector}')
                return eles.first
            raise NoSuchElementException(f'查找第一个元素失败,没有定位到元素: {str(selector)}')
        except Exception as e:
            log.log_error(f'查找第一个元素失败: {str(selector)}，{repr(e)}')
            raise e

    # 查找元素--多个
    def element_find_elements(self, selector):
        """
        :param selector: 定位方式,字符串
        :return:
        """
        try:
            eles = self.find_elements(selector)
            return eles
        except Exception as e:
            log.log_error(f'定位元素失败: {selector},{repr(e)}')
            raise e

    # 查找元素找到全部
    def find_elements(self, selector):
        locator_params = {'has_text': None, 'has_not_text': None, 'has': None, 'has_not': None}
        try:
            if selector[0].lower() == 'locator':
                # 如果有参数，替换内容
                if len(selector) > 2:
                    locator_params.update(selector[2])
                count = 0
                ele = None
                for i in range(10):
                    log.log_info(f'查找第{str(i+1)}次')
                    ele = self.page.locator(selector[1], has_text=locator_params['has_text'],
                                            has_not_text=locator_params['has_not_text'],
                                            has=locator_params['has'], has_not=locator_params['has_not'])
                    count = ele.count()
                    if count > 0:
                        break
                    self.wait.wait_time(0.5)
                log.log_info(f'locator元素定位成功: {selector}, 个数：{count}')
            else:
                ele = self.element_find_by(selector)
            return ele
        except Exception as e:
            log.log_error(f'定位元素失败: {selector},{repr(e)}')
            raise e

    # get_by定位元素
    def element_find_by(self, selector):
        """
        :param selector: 定位方式，[by_xxx, 定位内容，参数传字典]
        :return: 返回所有元素
        """
        get_by_params = {'text': None, 'exact': None, 'test_id': None, 'checked': None, 'disabled': None, 'role': None,
                         'expanded': None, 'include_hidden': None, 'level': None, 'name': None, 'pressed': None,
                         'selected': None}
        # 如果有参数,替换内容
        if len(selector) > 2:
            get_by_params.update(selector[2])
        select_type = selector[0].lower() if 'by_' in selector[0] else 'by_'+selector[0].lower()
        try:
            if select_type in ['by_ale_text', 'by_label', 'by_placeholder', 'by_text', 'by_title']:
                func = eval(f'self.page.get_{select_type}')
                ele = func(selector[1], text=get_by_params['text'], exact=get_by_params['exact'])
            elif select_type == 'by_role':
                ele = self.page.get_by_role(role=get_by_params['role'], checked=get_by_params['checked'],
                                            disabled=get_by_params['disabled'], expanded=get_by_params['expanded'],
                                            include_hidden=get_by_params['include_hidden'], level=get_by_params['level'],
                                            name=get_by_params['name'], pressed=get_by_params['pressed'],
                                            selected=get_by_params['selected'])
            elif 'test_id' in selector[0]:
                ele = self.page.get_by_test_id(get_by_params['test_id'])
            else:
                raise NoSuchLocatorException(f'不存在的的定位方式：get_by_{select_type}')
            log.log_info(f'get_{select_type}定位成功')
            return ele
        except Exception as e:
            log.log_error(f'get_{select_type}定位元素失败，{repr(e)}')
            raise e

    # 等待直到元素出现,并返回第一个元素
    def element_wait_for_element(self, selector, timeout=5, state=None, strict=None):
        """
        等待元素出现
        :param selector: 定位方式,str格式
        :param timeout: 超时时间，单位秒
        :param state:
        :param strict:
        :return: 返回元素第一个
        """
        try:
            self.page.wait_for_selector(selector, timeout=int(timeout)*1000,state=state, strict=strict)
            log.log_info(f'等待直到元素出现成功')
            return self.page.locator(selector).first
        except Exception as e:
            log.log_error(f'等待元素出现失败，{repr(e)}')
            raise e

    # 获取元素个数
    def element_count(self, selector):
        """
        获取元素个数
        :param selector: 定位方式
        :return: 元素个数
        """
        try:
            if isinstance(selector, list):
                selector = self.element_find_elements(selector)
            count = selector.count()
            log.log_info(f'获取元素个数成功：{count}')
            return count
        except Exception as e:
            log.log_error(f'获取元素个数失败，{repr(e)}')
            raise e

    # 元素左键点击
    def element_click(self, selector):
        """
        元素左键单击
        :param selector: 传元素，或者定位方式，传元素直接点击，传定位方式先定位
        :return:
        """
        try:
            # 列表先定位
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
                selector.click()
            # 字符串直接点击
            else:
                self.page.click(selector)
            log.log_info('点击元素成功')
        except Exception as e:
            log.log_error('点击元素失败: '+repr(e))
            raise('元素点击失败: '+repr(e))

    # 输入
    def element_fill(self, selector, text):
        """
        输入文本
        :param selector: 元素或定位方式
        :param text: 要输入的文本内容
        :return:
        """
        try:
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
                selector.fill(text)
            else:
                self.page.fill(selector, text)
            log.log_info(f'输入成功： {text}')
        except Exception as e:
            log.log_error(f'输入失败： {text}，'+repr(e))
            raise e

    # 双击
    def element_double_click(self, selector):
        """
        元素双击
        :param selector: 传元素，或者定位方式，传元素直接点击，传定位方式先定位
        :return:
        """
        try:
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
                selector.dbclcik()
            else:
                self.page.dblclick(selector)
            log.log_info('双击元素成功')
        except Exception as e:
            log.log_error('双击元素失败： '+repr(e))
            raise('元素双击失败： '+repr(e))

    # 清空输入框内容
    def element_clear(self, selector):
        """
        清空文本内容
        :param selector: 传元素，或者定位方式，传元素直接点击，传定位方式先定位
        """
        try:
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
                selector.clear()
            else:
                self.page.clear(selector)
            log.log_info('输入框清空成功')
        except Exception as e:
            log.log_error('输入框清空失败：' + repr(e))
            raise ('输入框清空失败：' + repr(e))

    # 右键点击
    def element_context_click(self, selector):
        """
        :param selector: 元素或者定位方式
        :return:
        """
        try:
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
                selector.click(button='right')
            else:
                self.page.click(selector, button='right')
            log.log_info('右键单击成功')
        except Exception as e:
            log.log_error('右键单击失败：' + repr(e))
            raise ('右键单击失败：' + repr(e))

    # 某个键+鼠标左键点击
    def element_click_with(self, key, selector):
        """
        某个键+鼠标左键点击，shift,alt,ctr,meta
        :param key: 要按住的键
        :param selector: 元素或者定位方式
        :return:
        """
        key = key[0].upper+key[1:]
        if key not in ["Alt", "Control", "Meta", "Shift"]:
            log.log_error(f'{key}不存在，点击失败')
            raise 'key不存在'
        try:
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
                selector.click(modifiers=key)
            else:
                self.page.click(selector, modifiers=key)
            log.log_info(f'{key}+左键单击成功')
        except Exception as e:
            log.log_error(f'{key}+左键单击成功' + repr(e))
            raise (f'{key}+左键单击成功' + repr(e))

    # 单击保持
    def element_click_and_hold(self, selector, seconds=1):
        """
        :param selector:
        :param seconds:保持的时间,单位秒，默认1秒
        :return:
        """
        try:
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
                selector.click(delay=seconds*1000)
            else:
                self.page.click(selector, delay=seconds*1000)
            log.log_info(f'单击并保持<{str(seconds)}>秒成功')
        except Exception as e:
            log.log_error(f'单击并保持<{str(seconds)}秒失败>'+repr(e))
            raise(f'单击并保持<{str(seconds)}秒失败>'+repr(e))

    # 鼠标悬停
    def element_hover(self, selector):
        """
        :param selector:元素或定位方式
        :return:
        """
        try:
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
                selector.hover()
            else:
                self.page.hover(selector)
            log.log_info('悬停成功')
        except Exception as e:
            log.log_error('悬停失败：' + repr(e))
            raise ('悬停失败：' + repr(e))

    # 在指定元素上，点击键盘键位
    def element_press_key(self, selector, key):
        """
        :param selector: 元素或定位方式
        :param key: 要按的键位
        :return:
        """
        key = str(key)
        try:
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
                selector.press()
            else:
                self.page.press(selector, key)
            log.log_info(f'按下<{key}>成功')
        except Exception as e:
            log.log_error(f'按下<{key}>失败： ' + repr(e))
            raise (f'按下<{key}>失败：' + repr(e))

    # 检查元素是否可见
    def element_is_visible(self, selector):
        """
        检查元素是否可见
        :param selector: 定位方式或元素或元素句柄
        :return: bool
        """
        try:
            if isinstance(selector, str):
                visible = self.page.is_visible(selector)
            else:
                selector = self.element_find_element(selector)
                visible = selector.is_visible()
            log.log_info(f'检查元素可见性成功: {visible}')
            return visible
        except Exception as e:
            log.log_error(f'检查元素可见性失败，{repr(e)}')
            raise e

    # 检查元素是否可用
    def element_is_enabled(self, selector):
        """
        检查元素是否可用
        :param selector: 定位方式或元素或元素句柄
        :return: bool
        """
        try:
            if isinstance(selector, str):
                enable = self.page.is_enabled(selector)
            else:
                selector = self.element_find_element(selector)
                enable = selector.is_enabled()
            log.log_info(f'检查元素可用性成功')
            return enable
        except Exception as e:
            log.log_error(f'检查元素可用性失败，{repr(e)}')
            raise e

    # 检查元素是否被选中
    def element_is_checked(self, selector):
        """
        检查元素是否被选中
        :param selector: 定位方式或元素或元素句柄
        :return: bool
        """
        try:
            if isinstance(selector, str):
                check = self.page.is_checked(selector)
            else:
                selector = self.element_find_element(selector)
                check = selector.is_checked()
            log.log_info(f'检查元素是否选中成功')
            return check
        except Exception as e:
            log.log_error(f'检查元素是否选中失败，{repr(e)}')
            raise e

    # 检查元素是否被禁用
    def element_is_disabled(self, selector):
        """
        检查元素是否被禁用
        :param selector: 定位方式或元素或元素句柄
        :return: bool
        """
        try:
            if isinstance(selector, str):
                check = self.page.is_disabled(selector)
            else:
                selector = self.element_find_element(selector)
                check = selector.is_disabled()
            log.log_info(f'检查元素是否可操作成功')
            return check
        except Exception as e:
            log.log_error(f'检查元素是否可操作失败，{repr(e)}')
            raise e

    # 获取元素文本内容
    def element_get_text(self, selector):
        """

        :param selector: 元素或定位方式
        :return:
        """
        try:
            if isinstance(selector, str):
                text = self.page.inner_text(selector)
            else:
                selector = self.element_find_element(selector)
                text = selector.inner_text()
            log.log_info(f'获取元素文本内容成功:{text}')
            return text
        except Exception as e:
            log.log_error(f'获取元素文本内容失败，{repr(e)}')
            raise e

    # 获取元素属性
    def element_get_attribute(self, selector, attribute):
        """

        :param selector:元素或定位方式
        :param attribute:要获取的属性名
        :return:
        """
        try:
            if isinstance(selector, str):
                attr = self.page.get_attribute(selector, attribute)
            else:
                selector = self.element_find_element(selector)
                attr = selector.get_attribute(attribute)
            log.log_info(f'获取元素属性成功:{attribute}')
            return attr
        except Exception as e:
            log.log_error(f'获取元素属性失败，{repr(e)}')
            raise e

    # 获取元素坐标
    def element_get_position(self, selector):
        """

        :param selector: 定位方式或元素
        :return:x:横坐标，y：纵坐标，w：宽度，h：高度
        """
        try:
            if isinstance(selector, list):
                selector = self.element_find_element(selector)
            position = selector.bounding_box()
            log.log_info(f'获取元素坐标成功:{str(position)}')
            return position
        except Exception as e:
            log.log_error(f'获取元素坐标失败，{repr(e)}')
            raise e
